using System;
using System.Collections.Generic;
using CfgTable;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.GamePlay;

namespace IQIGame.Onigao.Logic
{
    public class Skill
    {
        public int skillID;
        public int lv = 1;
        public CfgSkill config;
        public SkillPart mainPart;
        public SkillPart enablePart;
        public SkillPart disablePart;
        public SkillPart[] parts;
        public SkillTrigger[] triggers;

        public Dictionary<long, SkillPart> partsDict = new Dictionary<long, SkillPart>();

        public IReadOnlyList<int> aiTargetSort;

        public Unit executer;
        public bool activeSkill => this.mainPart != null;

        public bool RemoveSign;

        // 当前正在执行的次数
        public int executing { get; private set; }

        public int cost;
        public int curCd;
        public int initCd;
        public int norCd;

        private ESkillType mRealSkillType;

        public ESkillType skillType
        {
            get => this.tempType == ESkillType.None ? this.mRealSkillType : this.tempType;
            set => this.mRealSkillType = value;
        }

        public ESkillType tempType;

        public void Execute(SelectParam input)
        {
            if (this.CanUsed() && this.SkillCost())
            {
                if (this.norCd > 0)
                {
                    this.curCd = this.norCd;
                }

                this.executer.battle.playCtrl.triggerCtrl.Broadcast(EBattleTriggerType.Battle_ExecuteSkill, this.mainPart, input, default(object), false);
                ExecutePart(this.mainPart, input);
            }
        }

        public void Trigger(SkillTrigger trigger, SelectParam input, object param = null)
        {
            var rCustom = this.executer.GetComponent<CustomPropertyComponent>(ETComponentType.CustomPropertyComponent);
            if (rCustom?.GetProperty<int>(ECustomProperty.ForbidTriggerSkill) > 0)
            {
                return;
            }

            var rTriggerPartPart = trigger.GetTriggerPart(param);
            if (rTriggerPartPart != null)
            {
                var rComp = this.executer.GetComponent<SkillComponent>(ETComponentType.SkillComponent);
                if (!rComp.OnTrigger(this.skillID))
                {
                    return;
                }

                this.executer.battle.playCtrl.triggerCtrl.Broadcast(EBattleTriggerType.Battle_ExecuteSkill, rTriggerPartPart, input, param, true);
                ExecutePart(rTriggerPartPart, input, param);
                if (input != null)
                {
                    ClassPool.Put(input);
                }
            }
        }


        public void Enable()
        {
            for (int i = 0; i < this.parts.Length; i++)
            {
                this.parts[i]?.OnEnable();
            }

            for (int i = 0; i < this.triggers.Length; i++)
            {
                this.triggers[i]?.Enable();
            }

            if (this.enablePart != null)
            {
                var rVirInput = ClassPool.Get<SelectParam>();
                rVirInput.unit = this.executer;
                rVirInput.pos = rVirInput.unit.pos;
                this.ExecutePart(this.enablePart, rVirInput);
                ClassPool.Put(rVirInput);
            }
        }

        public void Disable()
        {
            if (this.disablePart != null)
            {
                var rVirInput = ClassPool.Get<SelectParam>();
                rVirInput.unit = this.executer;
                rVirInput.pos = rVirInput.unit.pos;
                this.ExecutePart(this.disablePart, rVirInput);
                ClassPool.Put(rVirInput);
            }

            for (int i = 0; i < this.parts.Length; i++)
            {
                if (this.parts[i] != null)
                {
                    this.parts[i].OnDisable();
                }
            }

            for (int i = 0; i < this.triggers.Length; i++)
            {
                this.triggers[i]?.Disable();
            }
        }

        public bool CanUsed()
        {
            if (this.curCd > 0)
            {
                return false;
            }

            if (this.cost > 0)
            {
                var rAttr = this.executer.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
                var nCurSp = rAttr?.Get(EAttributeType.SP).ToInt() ?? 0;
                return nCurSp > this.cost;
            }

            return true;
        }

        private bool SkillCost()
        {
            if (this.cost > 0)
            {
                var rAttr = this.executer.GetComponent<AttributeComponent>(ETComponentType.AttributeComponent);
                var nCurSp = rAttr?.Get(EAttributeType.SP).ToInt() ?? 0;
                if (nCurSp > this.cost)
                {
                    rAttr.Add(EAttributeType.SP, -this.cost);
                    return true;
                }

                return false;
            }

            return true;
        }

        private void ExecutePart(SkillPart rPart, SelectParam rSelectParam, object param = null)
        {
            if (rPart == null)
            {
                return;
            }

            this.executing++;
#if UNITY_EDITOR
            if (this.executing > 30)
            {
                LogGame.LogWarning($"此技能已经执行{this.executing}次，可能存在死循环");
            }
#endif
            var rResp = ClassPool.Get<SkillResponse>();
            rResp.curPart = rPart;
            while (rResp.curPart != null)
            {
                rResp.curPart.Execute(ref rResp, rSelectParam, param);
                rResp.curPart = rResp.nextPart;
            }

            ClassPool.Put(rResp);
            this.executing--;

            if (this.RemoveSign && this.executing <= 0)
            {
                this.Dispose();
            }
        }

        public void Dispose()
        {
            this.Disable();
            this.executer = null;
            for (int i = 0; i < this.parts.Length; i++)
            {
                ClassPool.Put(this.parts[i]);
            }

            for (int i = 0; i < this.triggers.Length; i++)
            {
                this.triggers[i].Dispose();
                this.triggers[i].Free();
            }
        }

#if UNITY_EDITOR
        public override string ToString()
        {
            string s = $"[{this.skillID}]-[{this.lv}]\n";
            var rPart = this.mainPart;
            if (rPart != null)
            {
                s += "主Part:\n";
                while (rPart != null)
                {
                    s += rPart.ToString();
                    rPart = rPart.next;
                    if (rPart != null)
                    {
                        s += "->";
                    }
                    s += "\n";
                }

                s += "----------------\n";
            }

            s += "触发效果：\n";
            for (int i = 0; i < this.triggers.Length; i++)
            {
                var rTrigger = this.triggers[i];
                s += $"[{rTrigger.ToString()}]  触发 ";
                if (rTrigger.hasCondition)
                {
                    var rTrue = this.partsDict[rTrigger.triggerCondiditon.truePart];
                    var rFalse = this.partsDict[rTrigger.triggerCondiditon.truePart];

                    s += $"公式[{rTrigger.triggerCondiditon.CheckFormula}]=>[{rTrue}/{rFalse}]";
                }
                else
                {
                    var rTriggerPart = this.partsDict[rTrigger.triggerPart];
                    while (rTriggerPart != null)
                    {
                        s += $"[{rTriggerPart}]";
                        rTriggerPart = rTriggerPart.next;
                        if (rTriggerPart != null)
                        {
                            s += "->";
                        }

                        s += "\n";
                    }
                }

                s += "\n";
            }

            return s;
        }
#endif
    }

    public class SkillResponse : IReusableClass
    {
        public SkillPart curPart;
        public SkillPart nextPart;

        public List<SkillEffectiveContext> partContext = new List<SkillEffectiveContext>();

        public uint MaxStore => 5;

        public void OnReset()
        {
            for (int i = 0; i < this.partContext.Count; i++)
            {
                ClassPool.Put(partContext[i]);
            }

            this.partContext.Clear();
            this.curPart = null;
            this.nextPart = null;
        }

        public SkillEffectiveContext CreateContext()
        {
            var rContext = ClassPool.Get<SkillEffectiveContext>();
            this.partContext.Add(rContext);
            return rContext;
        }
    }

    [Flags]
    public enum ESkillType
    {
        None,
#if UNITY_EDITOR
        [UnityEngine.InspectorName("1.普通攻击")]
#endif
        NorAtk = 1 << 1,
#if UNITY_EDITOR
        [UnityEngine.InspectorName("2.主动技能")]
#endif
        Skill = 1 << 2,
#if UNITY_EDITOR
        [UnityEngine.InspectorName("3.大招")]
#endif
        BigSkill = 1 << 3,
#if UNITY_EDITOR
        [UnityEngine.InspectorName("4.被动技能")]
#endif
        Passive = 1 << 4,
#if UNITY_EDITOR
        [UnityEngine.InspectorName("5.宠物技能")]
#endif
        PetSkill = 1 << 5,
    }
}